// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_WASM_WASM_IMPORT_WRAPPER_CACHE_H_
#define V8_WASM_WASM_IMPORT_WRAPPER_CACHE_H_

#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif  // !V8_ENABLE_WEBASSEMBLY

#include "src/wasm/wasm-wrapper-cache.h"

namespace v8::internal::wasm {

struct ImportWrapperCacheKey {
  ImportWrapperCacheKey(ImportCallKind kind, const CanonicalSig* sig,
                        int expected_arity, Suspend suspend)
      : kind(kind),
        sig(sig),
        expected_arity(expected_arity),
        suspend(suspend) {}

  bool operator==(const ImportWrapperCacheKey& rhs) const = default;

  ImportCallKind kind;
  const CanonicalSig* sig;
  int expected_arity;
  Suspend suspend;

  class Hash {
   public:
    size_t operator()(const ImportWrapperCacheKey& key) const {
#if V8_HASHES_COLLIDE
      if (v8_flags.hashes_collide) return base::kCollidingHash;
#endif  // V8_HASHES_COLLIDE

      return base::hash_combine(static_cast<uint8_t>(key.kind),
                                key.sig->index(), key.expected_arity);
    }
  };
};

class WasmImportWrapperCache : public WasmWrapperCache<ImportWrapperCacheKey> {
 public:
  using CacheKey = ImportWrapperCacheKey;

#ifdef V8_ENABLE_TURBOFAN
  std::shared_ptr<WasmWrapperHandle> CompileWasmJsFastCallWrapper(
      Isolate* isolate, DirectHandle<JSReceiver> callable,
      const wasm::CanonicalSig* sig);
#endif

  V8_EXPORT_PRIVATE
  std::shared_ptr<WasmWrapperHandle> Get(Isolate* isolate,
                                         const CacheKey& cache_key);

  V8_EXPORT_PRIVATE
  bool HasCodeForTesting(ImportCallKind kind, const CanonicalSig* sig,
                         int expected_arity, Suspend suspend);

#ifdef DEBUG
  bool IsCompiledWrapper(WasmCodePointer code_pointer);
#endif

 protected:
  std::pair<WasmCompilationResult, WasmCode::Kind> CompileWrapper(
      Isolate* isolate, const CacheKey& cache_key) override;

 private:
  std::optional<Builtin> BuiltinForWrapper(const CacheKey&);
};

// Override WasmWrapperCache::EstimateCurrentMemoryConsumption if the derived
// class size diverges.
static_assert(sizeof(WasmWrapperCache<ImportWrapperCacheKey>) ==
              sizeof(WasmImportWrapperCache));

extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
    WasmWrapperCache<ImportWrapperCacheKey>;

}  // namespace v8::internal::wasm

#endif  // V8_WASM_WASM_IMPORT_WRAPPER_CACHE_H_
